package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.service.CartService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @program: gmall-parent
 * @author: Mr.Zhuo
 * @create: 2022-04-14 09:41
 **/
@Service
public class CartServiceImpl implements CartService {

    // 我们还需要远程调用product
    @Autowired
    private ProductFeignClient productFeignClient;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 根据用户Id 查询购物车列表
     *
     * @param userId
     * @return
     */
    @Override
    public List<CartInfo> getCartCheckedList(String userId) {
        //  获取的选中的购物车列表！
        String cartKey = this.getRedisKey(userId);
        //  获取到购物车集合数据：
        List<CartInfo> cartInfoList = this.redisTemplate.opsForHash().values(cartKey);
        List<CartInfo> cartInfos = cartInfoList.stream().filter(cartInfo -> {
            //  再次确认一下最新价格
            cartInfo.setSkuPrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()));
            return cartInfo.getIsChecked().intValue() == 1;
        }).collect(Collectors.toList());

        //  返回数据
        return cartInfos;

    }

    /**
     * 删除
     *
     * @param skuId
     * @param userId
     */
    @Override
    public void deleteCart(Long skuId, String userId) {
        String cartKey = this.getRedisKey(userId);
        redisTemplate.opsForHash().delete(cartKey, skuId.toString());
    }

    /**
     * // 更改选中状态
     *
     * @param userId
     * @param isChecked
     * @param skuId
     */
    @Override
    public void checkCart(String userId, Integer isChecked, Long skuId) {
        String cartKey = this.getRedisKey(userId);
        BoundHashOperations<String, String, CartInfo> boundHashOps = this.redisTemplate.boundHashOps(cartKey);
        CartInfo cartInfo = boundHashOps.get(skuId.toString());
        if (null != cartInfo) {
            cartInfo.setIsChecked(isChecked);
            boundHashOps.put(skuId.toString(), cartInfo);
        }
    }

    /**
     * 查询购物车
     *
     * @param userId
     * @param userTempId
     * @return
     */
    public List<CartInfo> getCartList(String userId, String userTempId) {
        // 创建返回对象
        List<CartInfo> noLoginCartInfoList = null;

        // 判断当前 是否是临时id
        if (!StringUtils.isEmpty(userTempId)) {
            // key值
            String userTempIdKey = this.getRedisKey(userTempId);
            // 从redis中获取到数据
            noLoginCartInfoList = redisTemplate.opsForHash().values(userTempIdKey);

            if (StringUtils.isEmpty(userId)) {
                //  这个是集合的排序
                if (noLoginCartInfoList != null && noLoginCartInfoList.size() > 0) {
                    noLoginCartInfoList.sort((o1, o2) -> {
                        // 如果想从大到小的话，我们需要从后面一个对比前面的
                        return o2.getUpdateTime().compareTo(o1.getUpdateTime());
                    });
                }
                // 返回数据集合
                return noLoginCartInfoList;
            }
        }

        //  属于登录
        List<CartInfo> LoginCartInfoList = null;
        // 获取redis中的数据，目前不可能临时用户id和登录用户id 都为空
        String redisKey = this.getRedisKey(userId);
        BoundHashOperations<String, String, CartInfo> boundHashOperations = redisTemplate.boundHashOps(redisKey);
        if (!CollectionUtils.isEmpty(noLoginCartInfoList)) {
            // 当前临时用户id存储的商品数据不为空
            for (CartInfo cartInfo : noLoginCartInfoList) {
                // 进行循环查询数据是否重复
                if (boundHashOperations.hasKey(cartInfo.getSkuId().toString())) {
                    // 冲突
                    // 更新时间
                    cartInfo.setUpdateTime(new Date());
                    // 获取最新的价格
                    cartInfo.setSkuPrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()));
                    // 数量相加
                    CartInfo noUserCartInfo = boundHashOperations.get(cartInfo.getSkuId().toString());
                    cartInfo.setSkuNum(cartInfo.getSkuNum() + noUserCartInfo.getSkuNum());
                    // 选中状态进行合并
                    if (cartInfo.getIsChecked() == 0 && noUserCartInfo.getIsChecked() == 1) {
                        // 只有这一种情况我们进行修改是否选中
                        cartInfo.setIsChecked(1);
                    }

                    // 更新完之后进行修改数据
                    boundHashOperations.put(cartInfo.getSkuId().toString(), cartInfo);


                } else {
                    // 直接将数据进行保存在缓存中
                    redisTemplate.opsForHash().put(redisKey, cartInfo.getSkuId().toString(), cartInfo);
                }
            }
            // 删除 临时用户id的值
            redisTemplate.delete(this.getRedisKey(userTempId));
        }

        //  获取到合并之后的数据：
        LoginCartInfoList = this.redisTemplate.boundHashOps(redisKey).values();
        if (CollectionUtils.isEmpty(LoginCartInfoList)) {
            return new ArrayList<>();
        }
        // 获取最新价格
        for (CartInfo cartInfo : LoginCartInfoList) {
            BigDecimal skuPrice = this.productFeignClient.getSkuPrice(cartInfo.getSkuId());
            cartInfo.setSkuPrice(skuPrice);
        }
        //  设置合并之后的排序结果！
        LoginCartInfoList.sort(((o1, o2) -> {
            return DateUtil.truncatedCompareTo(o2.getUpdateTime(), o1.getUpdateTime(), Calendar.SECOND);
        }));
        return LoginCartInfoList;
    }

    private String getRedisKey(String id) {
        return RedisConst.USER_KEY_PREFIX + id + RedisConst.USER_CART_KEY_SUFFIX;
    }

    /**
     * 添加商品到购物车
     *
     * @param skuId  商品id
     * @param userId 用户id
     * @param skuNum 商品数量
     */
    @Override
    public void addCat(Long skuId, String userId, Integer skuNum) {
        /**
         * 分析需求
         *
         * 1. 加入之前需要判断当前商品是否已经存在购物车
         *
         *      1.1 存在：我们只需要更改数量， 更改默认选定 isChecked
         *      1.2 不存在：我们需要进行存储到redis中
         *
         * 2. 排序：是按照我们加入购物车的加入时间来算的（谁先加入的早放在下面）
         *
         * 3. 价格问题，每次插入都是查询数据库进行查询实时价格
         *
         */

        // 判断是否存在redis，我们选择  hash数据类型进行存储

        // HSET key(user:userId:cart) field(skuId) value(skuInfo[实体类])
        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(
                RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX,
                skuId.toString());

        if (cartInfo != null) {
            // 当前商品不等于null 我们进行商品田间
            // 获取当前数据库最新的价格
            BigDecimal price = this.productFeignClient.getSkuPrice(skuId);
            cartInfo.setSkuPrice(price);
            // 进行数量相加
            cartInfo.setSkuNum(cartInfo.getSkuNum() + skuNum);
            // 更新时间
            cartInfo.setUpdateTime(new Date());

            // 更新被选中的状态
            if (cartInfo.getIsChecked() == 0) {
                cartInfo.setIsChecked(1);
            }
        } else {
            // 不存在当前用户
            cartInfo = new CartInfo();
            // 获取当前商品id的商品详细信息
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            if (skuInfo != null) {
                // 时间
                cartInfo.setUpdateTime(new Date());
                cartInfo.setCreateTime(new Date());
                // 商品的数量
                cartInfo.setSkuNum(skuNum);
                // 商品名称
                cartInfo.setSkuName(skuInfo.getSkuName());
                // 放入购物车的价格
                cartInfo.setCartPrice(skuInfo.getPrice());
                // 实时的价格
                cartInfo.setSkuPrice(productFeignClient.getSkuPrice(skuId));
                // 默认图片
                cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
                // 用户id
                cartInfo.setUserId(userId);
                // skuId
                cartInfo.setSkuId(skuId);
            } else {
                return;
            }
        }

        // 然后统一保存到redis
        redisTemplate.opsForHash().put(
                RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX,
                skuId.toString(),
                cartInfo);
    }
}
